home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 098 / xrefpas.arc / XREF.PAS
Encoding:
Pascal/Delphi Source File  |  1985-12-12  |  14.6 KB  |  523 lines

  1.  
  2. program TXREF;
  3.  
  4. {$V-}
  5. {$R+}
  6.  
  7. {  Program TXREF - Produce a Listing and Cross Reference for a Turbo Pascal
  8.    source file.
  9.  
  10.    You must have Turbo Toolbox from Borland International, Inc. in order to
  11.    compile this program.
  12.  
  13.    As written, this program assumes that you have an Epson FX-80 printer. It
  14.    may work on other printers if they are compatible enough.
  15.  
  16.    By Michael Quinlan
  17.       Version 1.0.0
  18.       12/1/84
  19.  
  20.   Known bugs:
  21.  
  22.     1. This program doesn't correctly handle certain types of constants;
  23.        the 'E' in a floating point constant will be considered a name as
  24.        will some hex constants. The procedure CopyTillAlpha needs to be
  25.        re-written to handle these things better.
  26.  
  27.     2. Numeric labels are not included in the cross reference.
  28.  
  29.     3. Names longer than 79 bytes may mess up the page alignment while
  30.        printing the cross reference.
  31.  
  32. }
  33.  
  34. const
  35.   LinesPerPage = 60;
  36.  
  37. Type
  38.   Str = String[127];
  39.   XrefRec = record
  40.               Name : Str;
  41.               Page : Integer;
  42.               Line : Integer;
  43.             end;
  44.  
  45. var
  46.   XrefVar       : XrefRec;
  47.   NumOnLine     : Integer;
  48.   CurLine       : Integer;
  49.   CurPage       : Integer;
  50.   SortResult    : Integer;
  51.   InFileName    : Str;
  52.   InFile        : Text;
  53.   Line          : Str;
  54.   CurPosn       : Integer;
  55.   CommentStatus : (NoComment, CurlyBracket, ParenStar);
  56.   InsideString  : Boolean;
  57.  
  58. const
  59.  NumReservedWords = 44;
  60.  BiggestReservedWord = 9;
  61.  ReservedWordList : array [1..NumReservedWords] of String[BiggestReservedWord]
  62.    = (
  63.   'ABSOLUTE', 'AND'     , 'ARRAY' , 'BEGIN', 'CASE'    , 'CONST' , 'DIV',
  64.   'DO'      , 'DOWNTO'  , 'ELSE'  , 'END'  , 'EXTERNAL', 'FILE'  , 'FOR',
  65.   'FORWARD' , 'FUNCTION', 'GOTO'  , 'IF'   , 'IN'      , 'INLINE', 'LABEL',
  66.   'MOD'     , 'NIL'     , 'NOT'   , 'OF'   , 'OR'      , 'PACKED', 'PROCEDURE',
  67.   'PROGRAM' , 'RECORD'  , 'REPEAT', 'SET'  , 'SHL'     , 'SHR'   , 'STRING',
  68.   'THEN'    , 'TO'      , 'TYPE'  , 'UNTIL', 'VAR'     , 'WHILE' , 'WITH',
  69.   'XOR'     , 'OVERLAY');
  70.  
  71. var
  72.   ReservedWordHashTable : array [1..NumReservedWords] of
  73.                             record
  74.                               WordPtr : Integer;
  75.                               NextPtr : Integer
  76.                             end;
  77.  
  78.  {$IC:SORT.BOX}  { Include the sort routines from Turbo ToolBox }
  79.  
  80. {=======================================================================}
  81. {  Printer Routines                                                     }
  82. {=======================================================================}
  83.  
  84. procedure Printer_Init;
  85. { Init the printer to 132 column mode }
  86. begin
  87.   Write(Lst, #15)
  88. end;
  89.  
  90. procedure Printer_Reset;
  91. { reset printer back to 80 column mode }
  92. begin
  93.   Write(Lst, #18)  { turn compressed mode off }
  94. end;
  95.  
  96. procedure Printer_Underscore;
  97. { Turn on underlines }
  98. begin
  99.   Write(Lst, #27'-1')  { turn on underlines }
  100. end;
  101.  
  102. procedure Printer_NoUnderscore;
  103. { Turn off underlines }
  104. begin
  105.   Write(Lst, #27'-0')  { turn off underlines }
  106. end;
  107.  
  108. procedure Printer_Eject;
  109. { Eject to a new page }
  110. begin
  111.   Write(Lst, #12)
  112. end;
  113.  
  114. {======================================================================}
  115. { Procedures for handling the hash table; this is used to speed up     }
  116. { checking for reserved words.                                         }
  117. {======================================================================}
  118.  
  119. function ReservedWordHash(var w : Str) : Integer;
  120. var
  121.   c : char;
  122.   h : integer;
  123.   i : integer;
  124.   n : integer;
  125. begin
  126.   h := 0;
  127.   n := 1;
  128.   for i := 1 to (length(w) div 2) do
  129.     begin
  130.       h := h xor ((Ord(w[n]) shl 8) or Ord(w[n+1]));
  131.       n := n + 2
  132.     end;
  133.   if n = length(w) then
  134.     h := h xor Ord(w[n]);
  135.   ReservedWordHash := ((h and $7FFF) mod NumReservedWords) + 1
  136. end;
  137.  
  138. procedure SetUpReservedWordHashTable;
  139. var
  140.   h : integer;
  141.   i : integer;
  142.   NewH : integer;
  143.   MinProbes, MaxProbes, NumProbes, TotProbes : integer;  { for debugging only }
  144.   AvgProbes : Real;  { for debugging only }
  145.  
  146.   function FindFreeEntry(h : integer) : integer;
  147.   begin
  148.     repeat
  149.       if h >= NumReservedWords then h := 1
  150.       else h := h + 1
  151.     until ReservedWordHashTable[h].WordPtr = 0;
  152.     FindFreeEntry := h
  153.   end;
  154.  
  155. begin
  156.   for i := 1 to NumReservedWords do
  157.     begin
  158.       ReservedWordHashTable[i].WordPtr := 0;
  159.       ReservedWordHashTable[i].NextPtr := 0
  160.     end;
  161.   for i := 1 to NumReservedWords do
  162.     begin
  163.       h := ReservedWordHash(ReservedWordList[i]);
  164.       if ReservedWordHashTable[h].WordPtr = 0 then
  165.         ReservedWordHashTable[h].WordPtr := i
  166.       else
  167.         begin { handle collisions }
  168.           { first find the end of the chain }
  169.           while ReservedWordHashTable[h].NextPtr <> 0 do
  170.             h := ReservedWordHashTable[h].NextPtr;
  171.           { now attach the new entry onto the end of the chain }
  172.           NewH := FindFreeEntry(h);
  173.           ReservedWordHashTable[h].NextPtr := Newh;
  174.           ReservedWordHashTable[NewH].WordPtr := i
  175.         end
  176.     end;
  177.  
  178. { the following is for debugging only }
  179.   (***********************************************************************
  180.  
  181.      D E B U G G I N G   C O D E   C O M M E N T E D   O U T
  182.  
  183.    ***********************************************************************
  184.  
  185.   { calculate the min, max, and average number of probes required into the
  186.     hash table }
  187.   TotProbes := 0;
  188.   MinProbes := MaxInt;
  189.   MaxProbes := 0;
  190.   for i := 1 to NumReservedWords do
  191.     begin
  192.       h := ReservedWordHash(ReservedWordList[i]);
  193.       NumProbes := 1;
  194.       while ReservedWordHashTable[h].WordPtr <> i do
  195.         begin
  196.           NumProbes := NumProbes + 1;
  197.           h := ReservedWordHashTable[h].NextPtr
  198.         end;
  199.       TotProbes := TotProbes + NumProbes;
  200.       if NumProbes > MaxProbes then MaxProbes := NumProbes;
  201.       if NumProbes < MinProbes then MinProbes := NumProbes
  202.     end;
  203.   AvgProbes := TotProbes / NumReservedWords;
  204.   writeln('RESERVED WORD HASH TABLE STATISTICS');
  205.   writeln(' Max Probes = ', MaxProbes);
  206.   writeln(' Min Probes = ', MinProbes);
  207.   writeln(' Avg Probes = ', AvgProbes:8:2)
  208.  
  209. *************************************************************************)
  210.  
  211. end;
  212.  
  213. {======================================================================}
  214. {  Procedures to set up the input file.                                }
  215. {======================================================================}
  216.  
  217. procedure UpStr(var s : Str);
  218. var
  219.   i : integer;
  220. begin
  221.   for i := 1 to length(s) do s[i] := UpCase(s[i])
  222. end;
  223.  
  224. function GetParm : Str;
  225. var
  226.   Parm : Str absolute CSeg:$80;
  227. begin
  228.   GetParm := Parm
  229. end;
  230.  
  231. function AskFileName : Str;
  232. var
  233.   f : Str;
  234. begin
  235.   Write('Name of file to cross reference: ');
  236.   Readln(f);
  237.   if f = '' then halt;  { provide an exit for the user }
  238.   AskFileName := f
  239. end;
  240.  
  241. function OpenInFile : boolean;
  242. begin
  243.   UpStr(InFileName);  { convert file name to upper case }
  244.   if Pos('.', InFileName) = 0 then InFileName := InFileName + '.PAS';
  245.   Assign(InFile, InFileName);
  246.   {$I-} Reset(InFile); {$I+}
  247.   OpenInFile := (IOResult = 0)
  248. end;
  249.  
  250. procedure GetInFile;
  251. begin
  252. { on entry, InFileName may already have the file name }
  253.   if InFileName = '' then InFileName := AskFileName;
  254.   while not OpenInFile do
  255.     begin
  256.       Writeln('Cannot open ', InFileName);
  257.       InFileName := AskFileName
  258.     end
  259. end;
  260.  
  261. procedure NewPage;
  262. begin
  263.   if CurPage = 0 then
  264.     begin
  265.       Writeln('Make sure printer is lined up at the top of the page and powered on.');
  266.       Write('Press Enter when ready... ');
  267.       readln;
  268.       Printer_Init  { set printer in 132 column mode }
  269.     end
  270.   else
  271.     Printer_Eject;
  272.   CurPage := CurPage + 1;
  273.   CurLine := 1;
  274.   Writeln(Lst, 'Page ', CurPage:5, 'Listing of ':60, InFileName);
  275.   Writeln(Lst)
  276. end;
  277.  
  278. procedure ReadLine;
  279. begin
  280.   Readln(InFile, Line);
  281.   if CurLine >= LinesPerPage then NewPage
  282.   else CurLine := CurLine + 1;
  283.   CurPosn := 1;
  284.   InsideString := FALSE;
  285.   Write(Lst, CurLine:2, ': ')
  286. end;
  287.  
  288. {======================================================================}
  289. {  Procedures to process the input file.                               }
  290. {======================================================================}
  291.  
  292. procedure CopyTillAlpha;
  293. { copy chars from Line to the printer until the start of a name is found }
  294. begin
  295.   while (CurPosn <= length(Line)) and
  296.          (not (Line[CurPosn] in ['A'..'Z','a'..'z','_']) or InsideString or
  297.           (CommentStatus <> NoComment)) do
  298.     begin
  299.       if CommentStatus = NoComment then
  300.         begin
  301.           if Line[CurPosn] = '''' then InsideString := not InsideString
  302.         end;
  303.       if not InsideString then
  304.         case CommentStatus of
  305.           NoComment : begin
  306.                         if Line[CurPosn] = '{' then CommentStatus := CurlyBracket
  307.                         else if CurPosn < length(Line) then
  308.                                begin
  309.                                  if Copy(Line, CurPosn, 2) = '(*' then
  310.                                    CommentStatus := ParenStar
  311.                                end
  312.                       end;
  313.           CurlyBracket : if Line[CurPosn] = '}' then CommentStatus := NoComment;
  314.           ParenStar    : if CurPosn < length(Line) then
  315.                            begin
  316.                              if Copy(Line, CurPosn, 2) = '*)' then
  317.                                CommentStatus := NoComment
  318.                            end
  319.         end; { Case }
  320.       Write(Lst, Line[CurPosn]);
  321.       CurPosn := CurPosn + 1
  322.     end
  323. end;
  324.  
  325. function Reserved(var w : Str) : boolean;
  326. var
  327.   h : integer;
  328.   r : (DontKnow, IsReserved, NotReserved);
  329. begin
  330.   h := ReservedWordHash(w);
  331.   r := DontKnow;
  332.   repeat
  333.     if w = ReservedWordList[ReservedWordHashTable[h].WordPtr] then
  334.       r := IsReserved
  335.     else if ReservedWordHashTable[h].NextPtr = 0 then
  336.       r := NotReserved
  337.     else h := ReservedWordHashTable[h].NextPtr
  338.   until r <> DontKnow;
  339.   Reserved := (r = IsReserved)
  340. end;
  341.  
  342. procedure WriteReserved(var w : Str);
  343. begin
  344.   Printer_Underscore;  { turn on underscores }
  345.   write(Lst, w);
  346.   Printer_NoUnderscore { turn off underscores }
  347. end;
  348.  
  349. procedure WriteWord(var Word, CapWord : Str);
  350. begin
  351.   XrefVar.Name := CapWord;
  352.   XrefVar.Page := CurPage;
  353.   XrefVar.Line := CurLine;
  354.   SortRelease(XrefVar);
  355.   write(Lst, Word)
  356. end;
  357.  
  358. procedure DoWord;
  359. var
  360.   wstart  : integer;
  361.   Word    : Str;
  362.   CapWord : Str;
  363. begin
  364.   wstart := CurPosn;
  365.   repeat
  366.     CurPosn := CurPosn + 1
  367.   until (CurPosn > length(Line)) or not (Line[CurPosn] in ['A'..'Z','a'..'z','_','0'..'9']);
  368.   Word := Copy(Line, wstart, CurPosn - wstart);
  369.   CapWord := Word;
  370.   UpStr(CapWord);  { Upper case version of the word }
  371.   if Reserved(CapWord) then
  372.     WriteReserved(Word)
  373.   else
  374.     WriteWord(Word, CapWord)
  375. end;
  376.  
  377. procedure Inp;
  378. begin
  379.   GetInFile;
  380.   CurLine := 1000;  { force page break on first line }
  381.   CurPage := 0;
  382.   CommentStatus := NoComment;
  383.   while not EOF(InFile) do
  384.     begin
  385.       ReadLine;
  386.       while CurPosn <= length(Line) do
  387.         begin
  388.           CopyTillAlpha;
  389.           if CurPosn <= length(Line) then DoWord
  390.         end;
  391.       Writeln(Lst)
  392.     end
  393. end;
  394.  
  395. {======================================================================}
  396. {  Procedure called by TurboSort to order the cross reference entries  }
  397. {======================================================================}
  398.  
  399. function Less;
  400. var
  401.   FirstRec  : XrefRec absolute X;
  402.   SecondRec : XrefRec absolute Y;
  403. begin
  404.   if FirstRec.Name = SecondRec.Name then
  405.     begin
  406.       if FirstRec.Page = SecondRec.Page then
  407.         Less := FirstRec.Line < SecondRec.Line
  408.       else
  409.         Less := FirstRec.Page < SecondRec.Page
  410.     end
  411.   else
  412.     Less := FirstRec.Name < SecondRec.Name
  413. end;
  414.  
  415. {======================================================================}
  416. {  Procedures to print the sorted cross reference                      }
  417. {======================================================================}
  418.  
  419. procedure Xref_NewPage;
  420. begin
  421.   Printer_Eject;
  422.   Writeln(Lst, 'C R O S S   R E F E R E N C E':54);
  423.   Writeln(Lst, 'Entries are PAGE:LINE':50);
  424.   Writeln(Lst);
  425.   CurLine := 0
  426. end;
  427.  
  428. procedure Xref_NewLine;
  429. begin
  430.   Writeln(Lst);
  431.   if CurLine >= LinesPerPage then Xref_NewPage
  432.   else CurLine := CurLine + 1;
  433.   NumOnLine := 0
  434. end;
  435.  
  436. procedure Xref_Write_Number(n, count : integer);
  437. { write "n" to Lst with "count" digits (add leading zeros) }
  438. var
  439.   s : Str;
  440.   i : integer;
  441. begin
  442.   for i := count downto 1 do
  443.     begin
  444.       s[i] := Chr((n mod 10) + Ord('0'));
  445.       n := n div 10
  446.     end;
  447.   s[0] := Chr(count);  { set correct string length }
  448.   write(Lst, s)
  449. end;
  450.  
  451. procedure Xref_Write;
  452. begin
  453.   if NumOnLine >= 8 then Xref_NewLine;
  454.   if NumOnLine = 0 then Write(Lst, '   ');
  455.   Write(Lst, ' ');
  456.   Xref_Write_Number(XrefVar.Page, 5);
  457.   Write(Lst, ':');
  458.   Xref_Write_Number(XrefVar.Line, 2);
  459.   NumOnLine := NumOnLine + 1
  460. end;
  461.  
  462. procedure Xref_NewName;
  463. begin
  464.   if (CurLine + 2) >= LinesPerPage then Xref_NewPage;
  465.   Write(Lst, XrefVar.Name);
  466.   Xref_NewLine
  467. end;
  468.  
  469. procedure Outp;
  470. var
  471.   CurName : Str;
  472. begin
  473.   Printer_Reset;  { put printer back into 80 column mode }
  474.   Xref_NewPage;
  475.   SortReturn(XrefVar);
  476.   CurName := XrefVar.Name;
  477.   Xref_NewName;
  478.   Xref_Write;
  479.   while not SortEOS do
  480.     begin
  481.       SortReturn(XrefVar);
  482.       if CurName <> XrefVar.Name then
  483.         begin
  484.           Xref_NewLine;
  485.           CurName := XrefVar.Name;
  486.           Xref_NewName
  487.         end;
  488.       Xref_Write
  489.     end;
  490.   Writeln(Lst);
  491.   Printer_Eject
  492. end;
  493.  
  494. {======================================================================}
  495. {  Main Program                                                        }
  496. {======================================================================}
  497.  
  498. begin
  499.   Write('Pascal Source Listing and Cross Reference Program V1.0.0');
  500.   Writeln('  By Michael Quinlan');
  501.   Writeln;
  502.   SetUpReservedWordHashTable;
  503.   InFileName := GetParm;
  504.   while (length(InFileName)>0) and (InFileName[1] = ' ') do
  505.     delete(InFileName, 1, 1);
  506.   SortResult := TurboSort(SizeOf(XrefRec));
  507.   writeln;
  508.   case SortResult of
  509.      0 : Writeln('Program Completed OK');
  510.      3 : Writeln('Insufficient Memory for Sort');
  511.      8 : Writeln('Illegal Item Length for Sort (Program Logic Error)');
  512.      9 : Writeln('More Than ', MaxInt, ' Items to be Sorted');
  513.     10 : Writeln('Sort Error, Disk Error or Disk Full?');
  514.     11 : Writeln('Write Error During Sort, Bad Disk?');
  515.     12 : Writeln('File Creation Error During Sort')
  516.   else
  517.     Writeln('Unknown Error ', SortResult, ' From Sort')
  518.   end; { Case }
  519.   if SortResult <> 0 then
  520.     Writeln('*** Sort Failed; Cross Reference Invalid or Incomplete')
  521. end.
  522.  
  523.